#ifndef _HELIX_MESH_TESTS_H_
#define _HELIX_MESH_TESTS_H_

// MeshTests.h
#include <cxxtest/TestSuite.h>
#include "../Helix/Log.h"
#include "../Helix/HObject.h"
#include "../Helix/Domain/HelixMesh.h"
#include <vector>

using namespace std;

using namespace helix;

class MeshTest : public CxxTest::TestSuite
{
public:

	float *testVertData;
	unsigned int *testFaceData;

	void setUp()
	{
		printf("\n\nMeshTest::");

		testVertData = new float[12];
		testVertData[0]=0.0;
		testVertData[1]=0.0;
		testVertData[2]=0.0;

		testVertData[3]=1.0;
		testVertData[4]=1.0;
		testVertData[5]=1.0;
		
		testVertData[6]=-1.0;
		testVertData[7]=-1.0;
		testVertData[8]=-1.0;
		
		testVertData[9]=1.0;
		testVertData[10]=1.0;
		testVertData[11]=1.0;


		testFaceData = new unsigned int[6];
		testFaceData[0] = 0;
		testFaceData[1] = 1;
		testFaceData[2] = 2;

		testFaceData[3] = 1;
		testFaceData[4] = 2;
		testFaceData[5] = 3;

	}

	void tearDown()
	{
		delete[] testVertData;
		delete[] testFaceData;
	}

	//This just tests the constructor of the Mesh class
	void testMesh( void )
	{
		printf("testMesh\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);

		vector<float> *verts = mesh.getVertData();
		float *rawVerts = mesh.getRawVertDataBuffer();
		for(int i=0;i<12;i++)
		{
			TS_ASSERT_EQUALS(testVertData[i],(*verts)[i]);
			TS_ASSERT_EQUALS(testVertData[i],rawVerts[i]);
		}
		TS_ASSERT_EQUALS(12,verts->size());

		vector<unsigned int> *faces = mesh.getFaceData();
		unsigned int *rawFaces = mesh.getRawFaceDataBuffer();
		for(int i=0;i<6;i++)
		{
			TS_ASSERT_EQUALS(testFaceData[i],(*faces)[i]);
			TS_ASSERT_EQUALS(testFaceData[i],rawFaces[i]);
		}
		TS_ASSERT_EQUALS(6,faces->size());

		TS_ASSERT_EQUALS(3,mesh.getVertsPerFace());
		TS_ASSERT_EQUALS(4,mesh.getNumberOfVerts());
		TS_ASSERT_EQUALS(2,mesh.getNumberOfFaces());
	}

	//Tests attaching vertex data buffers
	void testAttachBuffers( void )
	{
		printf("testAttachBuffers\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);

		mesh.attachDataBuffer(testVertData,Mesh::RGB_COLOR_BUFFER);
		mesh.attachDataBuffer(testVertData,Mesh::NORMAL_BUFFER);

		vector<float> *colors = mesh.getData(Mesh::RGB_COLOR_BUFFER);
		vector<float> *normals = mesh.getData(Mesh::NORMAL_BUFFER);
		float *rawCols = mesh.getRawDataBuffer(Mesh::RGB_COLOR_BUFFER);
		float *rawNorms = mesh.getRawDataBuffer(Mesh::NORMAL_BUFFER);
		for(int i=0;i<12;i++)
		{
			TS_ASSERT_EQUALS(testVertData[i],(*colors)[i]);
			TS_ASSERT_EQUALS(testVertData[i],rawCols[i]);
			TS_ASSERT_EQUALS(testVertData[i],(*normals)[i]);
			TS_ASSERT_EQUALS(testVertData[i],rawNorms[i]);
		}
		TS_ASSERT_EQUALS(12,normals->size());
		TS_ASSERT_EQUALS(12,colors->size());

		TS_ASSERT_EQUALS(3,mesh.getElementsPerVertex(Mesh::RGB_COLOR_BUFFER));
		TS_ASSERT_EQUALS(3,mesh.getElementsPerVertex(Mesh::NORMAL_BUFFER));

		TS_ASSERT_EQUALS(true,mesh.isBufferAvailable(Mesh::RGB_COLOR_BUFFER));
		TS_ASSERT_EQUALS(true,mesh.isBufferAvailable(Mesh::NORMAL_BUFFER));
	}

	//Tests availability of attached vertex data buffers
	void testBufferDataAvailable( void )
	{
		printf("testBufferDataAvailable\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);

		TS_ASSERT_EQUALS(false,mesh.isBufferAvailable(Mesh::RGB_COLOR_BUFFER));
		TS_ASSERT_EQUALS(false,mesh.isBufferAvailable(Mesh::NORMAL_BUFFER));
		TS_ASSERT_EQUALS(false,mesh.isBufferAvailable(Mesh::TEX_COORD_2D_BUFFER));

		mesh.attachDataBuffer(testVertData,Mesh::RGB_COLOR_BUFFER);
		mesh.attachDataBuffer(testVertData,Mesh::NORMAL_BUFFER);

		TS_ASSERT_EQUALS(true,mesh.isBufferAvailable(Mesh::RGB_COLOR_BUFFER));
		TS_ASSERT_EQUALS(true,mesh.isBufferAvailable(Mesh::NORMAL_BUFFER));
		TS_ASSERT_EQUALS(false,mesh.isBufferAvailable(Mesh::TEX_COORD_2D_BUFFER));
		
	}

	//Tests detaching vertex data buffers
	void testDetachBuffers( void )
	{
		printf("testDetachBuffers\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);

		mesh.attachDataBuffer(testVertData,Mesh::RGB_COLOR_BUFFER);
		mesh.attachDataBuffer(testVertData,Mesh::NORMAL_BUFFER);

		TS_ASSERT_EQUALS(true,mesh.isBufferAvailable(Mesh::RGB_COLOR_BUFFER));
		TS_ASSERT_EQUALS(true,mesh.isBufferAvailable(Mesh::NORMAL_BUFFER));

		mesh.detachDataBuffer(Mesh::RGB_COLOR_BUFFER);
		mesh.detachDataBuffer(Mesh::NORMAL_BUFFER);

		TS_ASSERT_EQUALS(false,mesh.isBufferAvailable(Mesh::RGB_COLOR_BUFFER));
		TS_ASSERT_EQUALS(false,mesh.isBufferAvailable(Mesh::NORMAL_BUFFER));
	}

	//Tests removing redundant vertices
	void testShareVerts( void )
	{
		printf("testShareVerts\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);
		mesh.attachDataBuffer(testVertData,Mesh::RGB_COLOR_BUFFER);

		TS_ASSERT_EQUALS(4,mesh.getNumberOfVerts());
		TS_ASSERT_EQUALS(2,mesh.getNumberOfFaces());

		mesh.shareVerts();

		TS_ASSERT_EQUALS(3,mesh.getNumberOfVerts());
		TS_ASSERT_EQUALS(2,mesh.getNumberOfFaces());

		//Make sure that the data is still valid
		float *rawVerts = mesh.getRawVertDataBuffer();
		unsigned int *rawFaces = mesh.getRawFaceDataBuffer();
		float *rawCols = mesh.getRawDataBuffer(Mesh::RGB_COLOR_BUFFER);
		for(int i=0;i<6;i++)
		{
			for(int j=0;j<3;j++)
			{
				TS_ASSERT_EQUALS(testVertData[testFaceData[i]*3+j],rawVerts[rawFaces[i]*3+j]);
				TS_ASSERT_EQUALS(testVertData[testFaceData[i]*3+j],rawCols[rawFaces[i]*3+j]);
			}
		}
	}

	//Tests adding redundant vertices so that there are vertsPerFace * numberOfFaces vertices
	void testUnShareVerts( void )
	{
		printf("testUnShareVerts\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);
		mesh.attachDataBuffer(testVertData,Mesh::RGB_COLOR_BUFFER);

		TS_ASSERT_EQUALS(4,mesh.getNumberOfVerts());
		TS_ASSERT_EQUALS(2,mesh.getNumberOfFaces());

		mesh.unShareVerts();

		TS_ASSERT_EQUALS(6,mesh.getNumberOfVerts());
		TS_ASSERT_EQUALS(2,mesh.getNumberOfFaces());

		//Make sure that the data is still valid
		float *rawVerts = mesh.getRawVertDataBuffer();
		unsigned int *rawFaces = mesh.getRawFaceDataBuffer();
		float *rawCols = mesh.getRawDataBuffer(Mesh::RGB_COLOR_BUFFER);
		for(int i=0;i<6;i++)
		{
			for(int j=0;j<3;j++)
			{
				TS_ASSERT_EQUALS(testVertData[testFaceData[i]*3+j],rawVerts[rawFaces[i]*3+j]);
				TS_ASSERT_EQUALS(testVertData[testFaceData[i]*3+j],rawCols[rawFaces[i]*3+j]);
			}
		}
	}

	void testLoadHMF( void )
	{
		printf("testLoadHMF\n");
		
		Mesh *mesh = MeshUtil::loadFromHMF("HelixTests/testdata/meshes/cube.hmf");

		TS_ASSERT_EQUALS(8,mesh->getNumberOfVerts());
		TS_ASSERT_EQUALS(6,mesh->getNumberOfFaces());
		TS_ASSERT_EQUALS(4,mesh->getVertsPerFace());
		TS_ASSERT(mesh->isBufferAvailable(Mesh::TEX_COORD_2D_BUFFER));
		TS_ASSERT(mesh->isBufferAvailable(Mesh::RGB_COLOR_BUFFER));

		MeshUtil::deleteMesh(mesh);
	}

	void testScaleMesh( void )
	{
		printf("testScaleMesh\n");
		
		Mesh mesh = Mesh(Mesh.TRIANGLE_MESH,6,testFaceData,12,testVertData);

		MeshUtil::scaleVertices(&mesh,2.0);

		vector<float> *verts = mesh.getVertData();
		for(int i=0;i<12;i++)
		{
			TS_ASSERT_DELTA(testVertData[i]*2.0f,(*verts)[i],0.00001);
		}
	}
};

#endif